package com.ctrlspace.core.compiler;

import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import javax.tools.DiagnosticCollector;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.ToolProvider;

import org.json.simple.JSONArray;
import org.json.simple.JSONObject;

import com.ctrlspace.model.Error;
import com.sun.source.util.JavacTask;

public class IJavaCompiler {
	
	public static String compile(String path, String targetDirectory, String cp) throws IOException{
		String stackTrace="";
		List<String> listOfPaths = getListOfPaths(path);
		stackTrace = getStackTrace(listOfPaths, path, targetDirectory, cp);
		System.out.println(stackTrace);
		return stackTrace;
	}
	
	public static List<String> getListOfPaths(String path){
		List<String> temp = new ArrayList<String>();
		List<String> subPaths = new ArrayList<String>();
		File file = new File(path);

		if(file.isDirectory()){
			String sub[] = file.list();
			
			for(int i=0; i<sub.length; i++){
				subPaths = getListOfPaths(new File(file, sub[i]).getPath());
				for(String s : subPaths){
					temp.add(s);
				}
			}
		}else{
			temp.add(path);
		}
		
		List<String> listOfPaths = new ArrayList<String>();
		for(int i=0; i<temp.size(); i++){
			if(temp.get(i).endsWith(".java")){
				listOfPaths.add(temp.get(i));
			}
		}
		
		return listOfPaths;
	}
	
	@SuppressWarnings("unchecked")
	public static String getStackTrace(List<String> listOfPaths, String path, String targetDirectory, String cp) throws IOException {
		String json = "";

		JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler();
		DiagnosticCollector<JavaFileObject> dc = new DiagnosticCollector<JavaFileObject>();
		
		Writer compileOutput = new StringWriter();
		Iterable<? extends JavaFileObject> compilationUnits = javaCompiler.getStandardFileManager(null, null, null).getJavaFileObjectsFromStrings(listOfPaths);
		JavacTask task = (JavacTask) javaCompiler.getTask(compileOutput, null, null,
				Arrays.asList("-d", targetDirectory, "-cp", cp), null, compilationUnits);
		task.call();

		JSONArray jo = new JSONArray();
		List<Error> listOfErrors = parse(putToList(compileOutput.toString()));

		compileOutput.close();

		JSONObject obj;
		for (Error e : listOfErrors) {
			obj = new JSONObject();
			obj.put("message", e.getMessage());
			obj.put("line", e.getLineNumber());
			String temp = e.getFileName();
			int offset = temp.indexOf(path);
			obj.put("filename", temp.substring(offset + path.length(), temp.length()));
			jo.add(obj);
		}

		json = jo.toJSONString();

		return json;
	}

	private static List<String> putToList(String contents) {
		List<String> list = new ArrayList<String>();
		String temp = "";
		for (int i = 0; i < contents.length(); i++) {
			if (contents.charAt(i) == '\n') {
				list.add(temp);
				temp = "";
			} else {
				temp += contents.charAt(i);
			}
		}
		return list;
	}

	private static List<Error> parse(List<String> contents) {
		List<Error> listOfErrors = new ArrayList<Error>();
		Error error = new Error();
		int pointer = 0, tempPtr = 0;
		
		for(String s: contents){
			System.out.println(s);
		}

		for (int i = 0; i < contents.size(); i++) {
			if (i == contents.size() - 1) {
				break;
			}
			error = new Error();
			String line = contents.get(i);

			pointer = findFileName(line);
			System.out.println(line);
			error.setFileName(line.substring(0, pointer - 1));

			tempPtr = pointer;
			pointer = findLineNumber(line, tempPtr);
			error.setLineNumber(Integer.valueOf(line.substring(tempPtr, pointer)));

			tempPtr = pointer + 1;
			pointer = findMessage(contents, i);
			error.setMessage(retrieveMessage(contents, tempPtr, i, pointer));

			listOfErrors.add(error);
			i = pointer;
		}

		return listOfErrors;
	}

	private static int findFileName(String line) {
		boolean found = false;
		int index = 0;
		for (int i = 0; i < line.length() && found == false; i++) {
			if (line.charAt(i) == '.') {
				if (line.substring(i + 1, i + 6).equals("java:")) {
					found = true;
					index = i + 6;
				}
			}
		}
		return index;
	}

	private static int findLineNumber(String line, int pointer) {
		while (Character.isDigit(line.charAt(pointer))) {
			pointer++;
		}
		return pointer;
	}

	private static int findMessage(List<String> contents, int lineNumber) {
		int endOfMessage = lineNumber - 1;
		boolean found = false;
		String line = "";
		while (found == false) {
			endOfMessage++;
			line = contents.get(endOfMessage);
			for (int i = 0; i < line.length(); i++) {
				if (line.charAt(i) == '^') {
					found = true;
				}
			}
		}
		return endOfMessage;
	}

	private static String retrieveMessage(List<String> contents, int pointer, int startLine, int endLine) {
		String message = "";

		while (startLine != endLine) {
			String line = contents.get(startLine);
			message += line.substring(pointer, line.length());
			message += "\n";
			startLine++;
			pointer = 0;
		}

		return message;
	}
}
